/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jxtafileshare;

import java.io.StringWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URL;
import java.util.Enumeration;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.Advertisement;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.StructuredDocument;
import net.jxta.protocol.*;
import net.jxta.credential.*;
import net.jxta.membership.*;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.platform.NetworkManager;
/**
 *
 * @author Danny
 */
public class GroupCreator {
    private PeerGroup myNetPeerGroup = null,
                      myPeerGroup = null,
                      myDiscoveredPeerGroup = null;
    private transient NetworkManager manager = null;
    private final static PeerGroupID myPeerGroupID = PeerGroupID.create(
                            URI.create("urn:jxta:uuid-4d6172676572696e204272756e6f202002"));
    private PeerGroupAdvertisement myGroupAdvertisement;

    public GroupCreator(NetworkManager man) {
        manager = man;
        if(!(manager == null)) {
            myNetPeerGroup = manager.getNetPeerGroup();
        } else {
            System.out.println("Network Manager does not exist!");
            System.exit(-1);
        }

        myPeerGroup = this.createPeerGroup(myNetPeerGroup);

        if(myPeerGroup != null) {
            System.out.println("Peer Group Created...");
            myDiscoveredPeerGroup = this.discoverPeerGroup(
                    myNetPeerGroup, myPeerGroupID);
            if(myDiscoveredPeerGroup != null) {
                System.out.println("Peer Group Found");
                this.joinGroup(myDiscoveredPeerGroup);
            }
        }
        System.out.println("Peer Group Joined");
        this.printXmlAdvertisement("XML Advertisement for" +
                "Peer Group Advertisement",
                myPeerGroup.getPeerGroupAdvertisement());
    }

    private PeerGroup createPeerGroup(PeerGroup rootPeerGroup) {
        PeerGroup localGroup = null;
        ModuleImplAdvertisement myGroupImpl;
        myGroupImpl = this.createPeerGroupModuleImplAdv(rootPeerGroup);

        DiscoveryService rootPeerGroupDiscoveryService =
                rootPeerGroup.getDiscoveryService();

        try {
            rootPeerGroupDiscoveryService.publish(myGroupImpl,
                                        PeerGroup.DEFAULT_LIFETIME,
                                        PeerGroup.DEFAULT_EXPIRATION);
            rootPeerGroupDiscoveryService.remotePublish(myGroupImpl,
                                        PeerGroup.DEFAULT_EXPIRATION);
        } catch(java.io.IOException e) {
            System.out.println("Can't Publish Module Advertisement");
            System.exit(-1);
        }
        myGroupAdvertisement =
                this.createPeerGroupAdvertisement(myGroupImpl);

        try {
            rootPeerGroupDiscoveryService.publish(myGroupAdvertisement,
                    PeerGroup.DEFAULT_LIFETIME,
                    PeerGroup.DEFAULT_EXPIRATION);
            rootPeerGroupDiscoveryService.remotePublish(myGroupAdvertisement,
                                    PeerGroup.DEFAULT_EXPIRATION);
             }catch(Exception e) {
                 e.printStackTrace();
                 System.exit(-1);
             }
             System.out.println("New Peer Group Advertisement has been published");

             if(myGroupAdvertisement == null) {
                 System.out.println("The group advertisement is null");
             }
             try {
                 myPeerGroup = rootPeerGroup.newGroup(myGroupAdvertisement);
             } catch(Exception e) {
                 e.printStackTrace();
                 System.exit(-1);
             }
             System.out.println("New PeerGroup has been created");

             return myPeerGroup;
    }
    
    private PeerGroupAdvertisement createPeerGroupAdvertisement(
            ModuleImplAdvertisement myModuleImplAdvertisement) {
        
        PeerGroupAdvertisement myPeerGroupAdvertisement =
                (PeerGroupAdvertisement)AdvertisementFactory.newAdvertisement(
                    PeerGroupAdvertisement.getAdvertisementType());
        
        myPeerGroupAdvertisement.setPeerGroupID(myPeerGroupID);
        myPeerGroupAdvertisement.setModuleSpecID(myModuleImplAdvertisement.getModuleSpecID());
        myPeerGroupAdvertisement.setName("MyGroup");
        myPeerGroupAdvertisement.setDescription("Test");
        
        return myPeerGroupAdvertisement;
    }

    private ModuleImplAdvertisement createPeerGroupModuleImplAdv(PeerGroup
                                    rootPeerGroup) {
        ModuleImplAdvertisement allPurposePeerGroupImplAdv = null;
        try {
            allPurposePeerGroupImplAdv = rootPeerGroup.getAllPurposePeerGroupImplAdvertisement();
        } catch(java.lang.Exception e) {
            System.out.println("Can't Execute: getAllPurposePeerGroupImplAdvertisement();");
            System.exit(-1);
        }
        ModuleImplAdvertisement PeerGroupModuleImplAdv =
                allPurposePeerGroupImplAdv;
        return PeerGroupModuleImplAdv;
    }

    private PeerGroup discoverPeerGroup(PeerGroup myNetPeerGroup,
                                PeerGroupID myPeerGroupID) {
        PeerGroup localPeerGroup;
        DiscoveryService myNetPeerGroupDiscoveryService = null;
        if(myNetPeerGroup != null) {
            myNetPeerGroupDiscoveryService =
                    myNetPeerGroup.getDiscoveryService();
        } else {
            System.out.println("Net Peer Group is null");
            System.exit(-1);
        }
        boolean isGroupFound = false;
        Enumeration localPeerGroupAdvertisementEnumeration = null;
        PeerGroupAdvertisement myPeerGroupAdvertisement = null;
        while(!isGroupFound) {
            try {
                localPeerGroupAdvertisementEnumeration =
                        myNetPeerGroupDiscoveryService.
                        getLocalAdvertisements(DiscoveryService.GROUP, "Name",
                        "MyGroup");
            } catch(java.io.IOException e) {
                System.out.println("Can't discover local adv");
            }
            if(localPeerGroupAdvertisementEnumeration != null) {
                while(localPeerGroupAdvertisementEnumeration.hasMoreElements()) {
                    PeerGroupAdvertisement pgAdv = null;
                    pgAdv = (PeerGroupAdvertisement)
                            localPeerGroupAdvertisementEnumeration.
                                nextElement();
                    if(pgAdv.getName().equals("MyGroup")) {
                        myPeerGroupAdvertisement = pgAdv;
                        isGroupFound = true;
                        break;
                    }
                }
            }
            try {
                Thread.sleep(5 * 1000);
            } catch(Exception e) {}
        }
        try {
            localPeerGroup = myNetPeerGroup.newGroup(myPeerGroupAdvertisement);
        }catch(net.jxta.exception.PeerGroupException e) {
            e.printStackTrace();
            return null;
        }
        return localPeerGroup;
    }

    void joinGroup(PeerGroup myLocalGroup) {
        StructuredDocument myCredentials = null;
        try {
            AuthenticationCredential myAuthenticationCredential =
                    new AuthenticationCredential(myLocalGroup, null, myCredentials);
            MembershipService myMembershipService =
                    myLocalGroup.getMembershipService();
            net.jxta.membership.Authenticator myAuthenticator =
                    myMembershipService.apply(myAuthenticationCredential);
            if(!myAuthenticator.isReadyForJoin()) {
                System.out.println("Authenticator is not complete");
                return;
            }
            myMembershipService.join(myAuthenticator);
            System.out.println("Group has been joined");
        } catch(Exception e) {
            System.out.println("Authentication failed - group not joined");
            e.printStackTrace();
            System.exit(-1);
        }
    }

    private void printXmlAdvertisement(String title, Advertisement adv) {
        String separator = "";
        for(int i = 0; i < title.length() + 4; i++) {
            separator = separator + "-";
        }
        System.out.println(separator);
        System.out.println("| " + title + " |");
        System.out.println(separator);

        System.out.println(adv.toString());

        System.out.println(separator);
    }

    public PeerGroupAdvertisement getGroupAdvertisement() {
        return myGroupAdvertisement;
    }

    public PeerGroup getNetPeerGroup() {
        if(myNetPeerGroup != null) {
            return myNetPeerGroup;
        } else {
            System.out.println("Warning: Net peer group is null");
            return null;
        }
    }
    public PeerGroup getPeerGroup() {
        if(myPeerGroup != null) {
            return myPeerGroup;
        } else {
            System.out.println("Warning: Peer group is null");
            return null;
        }
    }
}
